//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

#include "Base/Parallel/ParallelThread.h"
#include "Base/Parallel/Runnable.h"
#include "Base/Parallel/AsyncTask.h"

namespace Engine
{
namespace Base
{

	//
	// Parallel Thread Manager
	//

	class ParallelThreadManager : public BaseObject
	{
	// types
	private:
		typedef SyncEvent *				sync_event_ptr_t;


	// variables
	private:
		set< IParallelThreadPtr >		_threads;
		Mutex							_lockThreads;


	// methods
	public:
		ParallelThreadManager (const EngineSubSystemsRef ess) : BaseObject(ess)
		{
			ESS()->SetThreadManager( this );
		}


		~ParallelThreadManager ()
		{
			ReleaseAll();

			ESS()->SetThreadManager( null );
		}


		ParallelThreadPtr CreateThread ()
		{
			ParallelThreadPtr	thread = ParallelThread::New();
			AddThread( thread );

			thread->Start( ESS() );
			return thread;
		}


		void AddThread (const IParallelThreadPtr &thread)
		{
			SCOPELOCK( _lockThreads );
			_threads.AddOrReplace( thread );
		}


		void RemoveThread (const IParallelThreadPtr &thread)
		{
			SCOPELOCK( _lockThreads );
			_threads.Erase( thread );
		}


		void FlushAll ()
		{
			SCOPELOCK( _lockThreads );

			FOR( i, _threads )
			{
				_threads[i]->Flush();
			}
		}


		void ReleaseAll ()
		{
			SCOPELOCK( _lockThreads );

			FOR( i, _threads )
			{
				_threads[i]->Quit();
			}
		}


		IParallelThreadPtr GetCurrent ()
		{
			SCOPELOCK( _lockThreads );

			FOR( i, _threads )
			{
				if ( _threads[i]->IsCurrent() )
					return _threads[i];
			}
		}


		// Utils //
		static void Iterate (const IParallelThreadPtr &current, const IParallelThreadPtr &other)
		{
			CHECK( current.IsNotNull() and other.IsNotNull() );

			SyncEvent	ev( SyncEvent::AUTO_RESET );

			other->EnqueueFlushCommand( current );

			ParallelOp	op;
			FunctionBuilder::Create( op.func, &_Signal, &ev );
			
			other->Push( ToRValueRef( op ) );
			other->Flush();
			
			current->ProcessMessages();
			
			ev.Wait();
		}


	private:
		static void _Signal (const sync_event_ptr_t &ev)
		{
			ev->Signal();
		}
	};


}	// Base
}	// Engine